﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UBlockly.Scriptable;
using UBlockly.UI;
using System.Threading.Tasks;
using UBlockly.Compotent;
using UBlockly.Util;

namespace UBlockly.Graphic
{

    partial class BlockGraphic
    {
        static Dictionary<string, BlockDescribeData> sideBlockDescribeMap = new Dictionary<string, BlockDescribeData>(200);

        public static bool GetDescribeData(string functionName,out BlockDescribeData data)
        {
            if (sideBlockDescribeMap.TryGetValue(functionName, out data))
            {
                return true;
            }
            Debug.LogWarning($"BlockGraphic warnning,cannot get data from function:{functionName}");
            return false;
        }

        /// <summary>
        /// 分支函数块
        /// </summary>
        /// <returns></returns>
        static GameObject CreateBranchBlock(BlockDescribeData describeData,int branchCount)
        {
            if (sideBlockDescribeMap.ContainsKey(describeData.FunctionName))
            {
                Debug.LogWarning($"repeat functionName node:"+describeData.FunctionName);
                return null;
            }
            sideBlockDescribeMap.Add(describeData.FunctionName, describeData);
            for (int i = 0; i < branchCount; i++)
            {
                
            }

            BlockObject block = CreateBlock(describeData);
            
            SetBlockColor(block, describeData);
            SetBlockSprite(block, describeData);
            return block.gameObject;
        }

        /// <summary>
        /// 普通函数块
        /// </summary>
        /// <returns></returns>
        static BlockObject CreateNormalBlock(BlockDescribeData describeData)
        {
            BlockObject block = CreateBlock(describeData);
            SetBlockColor(block, describeData);
            SetBlockSprite(block, describeData);
            return block;
        }

        public static Node CreateNode(BlockObject blockGo)
        {
            var block = blockGo.GetComponent<BlockObject>();
            BlockDescribeData descData = default;
            if (sideBlockDescribeMap.TryGetValue(block.name, out descData))
            {
                NodeScriptable x = new NodeScriptable(descData);
                Node node = System.Activator.CreateInstance(ILTranslate.GetNodeType(x.ScriptType), block, x) as Node;
                return node;
            }
            else
            {
                Debug.LogError($"CreateNode error:{block.name}");
                return null;
            }
        }

        public static Node CreateNode(BlockDescribeData describeData, bool forDisplay = false)
        {
            if (!forDisplay)
            {
                //node会受工程管控
                if (sideBlockDescribeMap.ContainsKey(describeData.FunctionName))
                {
                    Debug.LogWarning($"repeat functionName node:" + describeData.FunctionName);
                    return null;
                }

                sideBlockDescribeMap.Add(describeData.FunctionName, describeData);
            }

            var block = CreateNormalBlock(describeData);
            if (block == null)
                throw new Exception("CreateNode error,functionname = "+describeData.FunctionName);
            NodeScriptable x = new NodeScriptable(describeData);
            return System.Activator.CreateInstance(ILTranslate.GetNodeType(x.ScriptType), block, x) as Node;
        }
        public static Node CreateNode(int classify,string functionDefine, string[] treeStrArray,params string[] paramDesc)
        {
            BlockDescribeData describeData = new BlockDescribeData(functionDefine, classify, paramDesc);
            return CreateNode(describeData, treeStrArray);
        }

        static Node CreateNode(BlockDescribeData describeData, string[] treeStrArray)
        {
            var block = CreateNormalBlock(describeData);
            if (block == null)
                throw new Exception("CreateNode error,functionname = " + describeData.FunctionName);
            NodeScriptable x = new NodeScriptable(treeStrArray, describeData.BlockDescs);
            return System.Activator.CreateInstance(ILTranslate.GetNodeType(x.ScriptType), block, x) as Node;
        }
    }

    public static partial class BlockGraphic
    {
        public static BlockObject CreateBlock(BlockDescribeData blockDescribeData)
        {
            if (blockDescribeData.ResultType == ILVarType.VoidR)
                return CreateBlock<SlotTypeBlock>(blockDescribeData);
            return CreateBlock<PackTypeBlock>(blockDescribeData);
        }
        static T CreateBlock<T>(BlockDescribeData blockDescribeData) where T : BlockObject
        {
            BlockObject block = new GameObject(blockDescribeData.FunctionName).AddComponent<T>();
            if (!string.IsNullOrEmpty(blockDescribeData.TryGetDesc(0)))
            {
                var bdesc = CreateDesc(block.transform, BlockGraphicSize.BlockDescFontSize, blockDescribeData.TryGetDesc(0), BlockGraphicColor.NodeDesc);
                bdesc.name = "BlockDesc";
                var len = Mathf.Clamp(bdesc.GetTextLength(), BlockGraphicSize.BlockDescMinWidth, BlockGraphicSize.BlockDescMaxWidth);
                bdesc.SetSize(new Vector2(len, BlockGraphicSize.DescHeight));
            }
            if (blockDescribeData.ParamTypesStr != null && blockDescribeData.ParamTypesStr.Length != 0)
            {
                var packer = new GameObject("Packer").AddComponent<PackerObject>();
                packer.transform.SetParent(block.transform);
                for (int i = 0; i < blockDescribeData.ParamTypesStr.Length; i++)
                {
                    var targetType = TranslateHelper.GetILVarTypeByVarTypeName(blockDescribeData.ParamTypesStr[i]);
                    if (targetType == ILVarType.VoidR)
                        throw new System.Exception("CreateBlock blockDescribeData.ParamTypes == VoidR");
                    CreateParamInfo(i, block, packer, blockDescribeData.TryGetDesc(1 + i),
                        blockDescribeData.ParamTypesStr[i]);
                }
            }
            if (blockDescribeData.ResultType == ILVarType.VoidR)
            {
                block.SetSlot(CreateSlotInfos(block.transform));
            }
            block.ReSize();
            return block as T;
        }

        static void SetBlockColor(BlockObject block, BlockDescribeData describeData)
        {
            var color = BlockGraphicColor.GetColor(GraphicHelper.ToColorDefine(describeData.ResultTypeStr));

            block.SetColor(color);
        }

        static void SetBlockSprite(BlockObject block, BlockDescribeData describeData)
        {
            var sprite = BlockGraphicSprite.GetSprite(GraphicHelper.ToSpriteDefine(describeData.ResultTypeStr));
            if(sprite != null)
                block.SetSprite(sprite);
            else
            {
                Debug.LogError($"BlockSprite:{describeData.ResultType} is null");
            }
        }

        static GameObject CreateParamInfo(int index,BlockObject block, PackerObject packer, string paramDesc,string paramTypeStr)
        {
            var paramCompotent = BlockGraphicGetter.GetGetterCompotent(GraphicHelper.ToGetterDefine(paramTypeStr));//BRes.GetParamGo(paramTypeStr);
            if (paramCompotent != null)
            {
                var texs = paramCompotent.GetComponentsInChildren<UnityEngine.UI.Text>();
                if (texs != null)
                {
                    for (int i = 0; i < texs.Length; i++)
                    {
                        texs[i].fontSize = BlockGraphicSize.ParamFontSize;
                    }
                }
                if (!string.IsNullOrEmpty(paramDesc))
                {
                    var pdesc = CreateDesc(packer.transform, BlockGraphicSize.ParamFontSize, paramDesc, BlockGraphicColor.NodeParamDesc);
                    pdesc.name = $"ParamDesc-{index}";
                    pdesc.SetSize(new Vector2(Mathf.Clamp(pdesc.GetTextLength(), BlockGraphicSize.PackerDescMinWidth, BlockGraphicSize.PackerDescMaxWidth), BlockGraphicSize.DescHeight));
                }
                var uparam = new GameObject($"Param-{index}").AddComponent<ParamObject>();
                uparam.transform.SetParent(packer.transform);
                paramCompotent.gameObject.AddComponent<DefaultTypeBlock>();
                paramCompotent.transform.SetParent(uparam.transform);
                paramCompotent.GetComponent<RectTransform>().sizeDelta = new Vector2(BlockGraphicSize.PackerCompnentMinWidth, BlockGraphicSize.PackerComponentMinHeight);
                packer.BindParamObject(index, paramTypeStr, uparam);
                block.SetPacker(packer);
                var color = BlockGraphicColor.GetColor(GraphicHelper.ToColorDefine(paramTypeStr));
                uparam.SetColor(color);
                return paramCompotent.gameObject;
            }
            return null;
        }

        static DescObject CreateDesc(Transform block,int fontSize, string text,Color color)
        {
            var bdesc = new GameObject("Desc").AddCompontentIfNoExist<DescObject>();
            bdesc.SetFont(BlockGraphicFont.GetFont(), fontSize, color);
            bdesc.transform.SetParent(block);
            bdesc.SetText(text);
            return bdesc;
        }

        static NSlotPair CreateSlotInfos(Transform block, int count = 2)
        {
            if (count == 0)
                return null;
            NSlotPair pair = new GameObject("SlotInfo").AddComponent<NSlotPair>();
            pair.transform.SetParent(block);
            pair.InitPair(count);
            return pair;
        }
    }
}


